package server

import (
	"encoding/json"
	"fmt"
	"time"

	"io/ioutil"
	"net/url"

	"log"
	"net/http"

	"golang.org/x/net/websocket"
)

func Start(address string) {
	http.HandleFunc("/createiso", createNodeIso)
	http.HandleFunc("/createraw", createNodeRaw)
	http.HandleFunc("/deletenode", deleteNode)
	http.HandleFunc("/node/exist", nodeExit)

	http.Handle("/node/watching", websocket.Handler(watchingNode))

	go listenAndCloseNodeTimeout()

	err := http.ListenAndServe(address, nil)

	if err != nil {
		log.Fatal(err)
		return
	}

}

func watchingNode(ws *websocket.Conn) {
	js := make(map[string]interface{})
	err := websocket.JSON.Receive(ws, &js)
	if err != nil {
		outputErr := make(map[string]interface{})
		outputErr["code"] = "-1"
		outputErr["error"] = err.Error()
		websocket.JSON.Send(ws, &outputErr)
		return
	}
	port := ""
	switch js["port"].(type) {
	case string:
		port = js["port"].(string)
	}
	timeout := time.Now().Add(time.Duration(int64(time.Second) * 60 * 60 * 24))
	ws.SetWriteDeadline(timeout)

	node := AllServer.Find(port)
	if node == nil {
		outputErr := make(map[string]interface{})
		outputErr["code"] = "-1"
		outputErr["error"] = "没有节点"
		websocket.JSON.Send(ws, &outputErr)
		return
	}
	node.isReadyMutex.Lock()
	node.ws[ws] = ws
	node.isReadyMutex.Unlock()

	for {
		err := websocket.JSON.Receive(ws, &js)
		if err != nil {
			node.isReadyMutex.Lock()
			delete(node.ws, ws)
			outputErr := make(map[string]interface{})
			outputErr["code"] = "-1"
			outputErr["error"] = err.Error()
			websocket.JSON.Send(ws, &outputErr)
			node.isReadyMutex.Unlock()
			break
		} else {
			if js["cmd"].(string) == "close" {
				node.isReadyMutex.Lock()
				delete(node.ws, ws)
				node.isReadyMutex.Unlock()
				break
			}
		}
	}
	fmt.Println("closed:", ws)
}
func nodeExit(w http.ResponseWriter, r *http.Request) {
	var js map[string]interface{} = make(map[string]interface{})

	body, _ := ioutil.ReadAll(r.Body)
	r.PostForm, _ = url.ParseQuery(string(body))
	nodeId := r.PostFormValue("nodeid")

	node := AllServer.Find(nodeId)
	if node == nil {
		js["code"] = "-1"
	} else {
		js["code"] = "0"
	}

	output, _ := json.Marshal(&js)

	w.Write(output)
}

func deleteNode(w http.ResponseWriter, r *http.Request) {
	body, _ := ioutil.ReadAll(r.Body)
	r.PostForm, _ = url.ParseQuery(string(body))
	nodeId := r.PostFormValue("nodeid")

	node := AllServer.Find(nodeId)
	if node != nil {
		node.Close()
		AllServer.Delete(nodeId)
	}
	var js map[string]interface{} = make(map[string]interface{})

	js["code"] = "0"
	js["msg"] = "销毁成功"
	output, _ := json.Marshal(&js)
	w.Write(output)
	fmt.Println("delete node:", nodeId)
	return
}

func createNodeIso(w http.ResponseWriter, r *http.Request) {
	var conf confSocket
	var js map[string]interface{} = make(map[string]interface{})

	body, _ := ioutil.ReadAll(r.Body)
	r.PostForm, _ = url.ParseQuery(string(body))

	conf.uid = r.PostFormValue("uid")
	conf.tid = r.PostFormValue("tid")
	conf.sid = r.PostFormValue("sid")

	node, err := NewServerNodeIso(&conf)
	if err != nil {
		js["code"] = "-1"
		js["msg"] = err.Error()
		output, _ := json.Marshal(&js)
		w.Write(output)
		return
	}

	port, _ := node.Id()
	AllServer.Add(port, node)
	local, _ := node.Local()

	js["code"] = "0"
	js["msg"] = "ok"
	js["node"] = local

	output, _ := json.Marshal(&js)
	w.Write(output)
	go node.DoIso()
}

func createNodeRaw(w http.ResponseWriter, r *http.Request) {
	var conf confSocket
	var js map[string]interface{} = make(map[string]interface{})

	body, _ := ioutil.ReadAll(r.Body)
	r.PostForm, _ = url.ParseQuery(string(body))

	conf.uid = r.PostFormValue("uid")
	conf.sid = r.PostFormValue("sid")

	node, err := NewServerNodeRaw(&conf)
	if err != nil {
		js["code"] = "-1"
		js["msg"] = err.Error()
		output, _ := json.Marshal(&js)
		w.Write(output)
		return
	}

	port, _ := node.Id()
	AllServer.Add(port, node)
	local, _ := node.Local()

	js["code"] = "0"
	js["msg"] = "ok"
	js["node"] = local
	js["name"] = node.name

	output, _ := json.Marshal(&js)
	w.Write(output)
	go node.DoRaw()

}

//每30分钟就检查所有节点，如果节点已经运行超过48小时，那么就销毁这个节点
func listenAndCloseNodeTimeout() {
	var timeout = time.Second * 60 * 60 * 24 * 2

	fmt.Println("listenAndCloseNodeTimeoutb")

	for {
		time.Sleep(time.Second * 60 * 30)
		fmt.Println("search timeout node,now is:", time.Now())
		nodes := AllServer.List()
		for id, node := range nodes {
			if time.Now().Sub(node.startTime) > timeout {
				node.Close()
				AllServer.Delete(id)
				fmt.Println("nodeid:", id, "is runing out 48 hours, kill it done!")
			}
		}

	}
}
